<?php

declare(strict_types=1);

namespace App\Job;

use App\Model\ChargeDetail;
use App\Model\ChargeOption;
use App\Model\Device;
use App\Model\DeviceFaultLog;
use App\Model\DevicePort;
use App\Model\DevicePortErrLog;
use App\Model\Normal;
use App\Model\Order;
use App\Services\DeviceService;
use App\Services\rx\RxService;
use Carbon\Carbon;
use Hyperf\AsyncQueue\Job;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\ApplicationContext;
use Swoole\Server;

class IotEvent extends Job
{
    public $data;

    public $fd;

    public $type;

    /**
     * 任务执行失败后的重试次数，即最大执行次数为 $maxAttempts+1 次
     */
    protected int $maxAttempts = 1;
    #[inject]
    protected RxService $rxService;

    public function __construct($fd, $type, $data)
    {
        $this->fd = $fd;
        $this->type = $type;
        $this->data = $data;
    }

    public function handle()
    {


        // 获取Redis实例
        $lockKey = md5("lock:{$this->fd}{$this->type}");
        // 尝试获取锁，3秒过期时间
        $lockAcquired = redis()->set($lockKey, time(), ['NX', 'EX' => 3]);
        // 如果无法获取锁，说明3秒内已经执行过，直接返回
        if (!$lockAcquired) {
            Normal::logger(sprintf(
                'IotEvent skipped due to rate limit - FD:%d Type:%s',
                $this->fd,
                $this->type
            ), 'iot-event-rate-limit');
            return;
        }

        try {
            switch ($this->type) {
                case 'heartbeat':
                    $this->handleHeart();
                    break;
                case 'login':
                    $this->handleLogin();
                    break;
                case 'close':
                    $this->handleClose();
                    break;
                case 'battery_status':
                    $this->handleBattery();
                    break;
                case 'alarm':
                    $this->handleAlarm();
                    break;
                case 'device_parameter_read_response':
                    $this->handleReadParameter();
                    break;
                case 'charge_progress':
                    $this->handleChargeProgress();
                    break;
                case 'start':
                    $this->handleStart();
                    break;
                case 'stop':
                    $this->handleStop();
                    break;

                default:
                    //do something
                    break;

            }
        } catch (\Exception $e) {
            Normal::logger($e->getMessage() . $e->getTraceAsString(), 'notify-event');
        }
    }


    public function handleLogin()
    {
        $existingDevice = Device::where('fd', $this->fd)
            ->where('sn', '!=', $this->data['charger_id'])
            ->first();
        try {
            if ($existingDevice) {
                Normal::logger('之前会强制设备下线：'.$this->fd.'--'.json_encode($this->data).'---'.json_encode($existingDevice), 'login-event');
                // 强制下线旧设备
//                $server = ApplicationContext::getContainer()->get(Server::class);
//                $server->close($existingDevice->fd);
                $existingDevice->update(['fd' => null]);
            }
            // 更新或创建当前设备
            Device::updateOrCreate(
                ['sn' => $this->data['charger_id']],
                [
                    'fd' => $this->fd,
                    'channel' => $this->data['channel'],
                    'protocol' => $this->data['versions']['protocol'],
                    'hardware' => $this->data['versions']['hardware'],
                    'software' => $this->data['versions']['software'],
                    'card_no' => $this->data['card_no']
                ]
            );
        } catch (\Exception $e) {
            Normal::logger($e->getMessage() . $e->getTraceAsString(), 'login-event');
        }
    }

    public function handleHeart()
    {
        $device = Device::query()->where('sn', (int)$this->data['charger_id'])
            ->with('port')
            ->first();
        if ($device) {
            try {
                $device->last_online_at = Carbon::now();
                $device->inline = 1;
                $device->signal = $this->data['signal'];
                $device->temperature = $this->data['temperature'];
                $device->channel = $this->data['channel'];
                $device->fd = $this->fd;
                $device->save();
                foreach ($this->data['gun_status'] as $portBin => $status) {
                    if($status == 0){
                        $usingOrder = Order::where('device_id', $device->id)
                            ->where('channel_number', $portBin + 1)
                            ->where('status', Order::STATUS_USING)
                            ->first();
                        if($usingOrder){
                            $this->data['stop_reason_text'] = '充电端口未充电';
                            $this->data['number'] = $usingOrder->number;
                            $this->handleStop();
                        }
                    }
                    DevicePort::updateOrCreate(
                        [
                            'device_id' => $device->id,
                            'port_bin' => $portBin + 1
                        ],
                        [
                            'status' => $status,
                            'sn' => $device->sn
                        ]
                    );
                }
            } catch (\Exception $e) {
                Normal::logger($e->getMessage() . $e->getTraceAsString(), 'heart-event');
            }
        } else {
            Normal::logger('fd--' . $this->fd . '----heartbeat-error' . json_encode($this->data), 'heart-event');
        }
    }

    public function handleClose()
    {
        $device = Device::where('fd', $this->fd)
            ->first();
        $deviceId = 0;
        if ($device) {
            $device->fd = null;
            $device->inline = 0;
            $device->save();
            $deviceId = $device->sn;
            DeviceFaultLog::create([
                'device_id' => $device->id,
                'message' => $device->sn.'设备掉线'.$this->fd,
            ]);
        }
        Normal::logger('fd--' . $this->fd . '----close-event'.'----'.$deviceId, 'order-event');
    }

    public function handleBattery()
    {
        $devicePort = DevicePort::where('sn', $this->data['charger_id'])
            ->where('port_bin', $this->data['port_bin'])
            ->first();
        if (!$devicePort) {
            return;
        }
        $devicePort->battery_volt = $this->data['battery_volt'] > 0 ? $this->data['battery_volt'] : 0;
        $devicePort->required_volt = $this->data['required_volt'] > 0 ? $this->data['required_volt'] : 0;
        $devicePort->required_curr = $this->data['required_curr'] > 0 ? $this->data['required_curr'] : 0;
        $devicePort->charge_volt = $this->data['charge_volt'] > 0 ? $this->data['charge_volt'] : 0;
        $devicePort->charge_curr = $this->data['charge_curr'] > 0 ? $this->data['charge_curr'] : 0;
        $devicePort->soc = $this->data['soc'];
        $devicePort->max_temperature = $this->data['max_temperature'];
        $devicePort->max_cell_volt = $this->data['max_cell_volt'] > 0 ? $this->data['max_cell_volt'] : 0;
        $devicePort->save();

    }

    public function handleAlarm()
    {
        $errModel = new DevicePortErrLog();
        $errModel->device_id = $this->data['charger_id'];
        $errModel->port_bin = $this->data['gun_no'];
        $errModel->date = $this->data['alarm_time'];
        $errModel->code = $this->data['alarm_code'];
        $errModel->status = $this->data['alarm_status'];
        $errModel->value = $this->data['alarm_value'];
        switch ($this->data['alarm_code']) {
            case 1001:
                $errModel->fault_message = '过压';
                break;
            case 1002:
                $errModel->fault_message = '欠压';
                break;
            case 1003:
                $errModel->fault_message = '高温';
                $errModel->value += 50;
                break;
            case 1004:
                $errModel->fault_message = '计量 故障';
                break;
            case 1005:
                $errModel->fault_message = '黏连 故障';
                break;
            case 1006:
                $errModel->fault_message = '空载';
                break;
            case 1007:
                $errModel->fault_message = '烟雾告警';
                break;
            default:
                $errModel->fault_message = '未知';
                break;
        }
        $errModel->save();

    }


    public function handleReadParameter()
    {
        $device = Device::where('sn', $this->data['charger_id'])->first();
        if (!$device) {
            Normal::logger(__METHOD__ . '--' . $this->data['charger_id'] . '---not--found', 'order-event');
            return;
        }
        $device->fill($this->data['parameters']);
        $device->save();
    }

    public function handleChargeProgress()
    {
        try{
            $order = Order::where('number', $this->data['number'])
                ->with('detail')
                ->with('charge')
                ->first();
            if (!$order) {
                Normal::logger(__METHOD__ . '--' . $this->data['number'] . '---not--found', 'order-event');
                return;
            }
            if($order->status == Order::STATUS_PAID){
                $order->status = Order::STATUS_USING;
            }
            if($this->data['power'] > $order->power){
                $order->power = $this->data['power'];
                $order->save();
            }
            if ($order->charge && $order->charge->type == 1) {
                $chargeDetail = ChargeDetail::where('charge_option_id', $order->charge_id)
                    ->where('type', 1)
                    ->where('min_power', '<=', $order->power)
                    ->where('max_power', '>=', $order->power)
                    ->first();
                if (!$chargeDetail) {
                    $minutes = 240;
                } else {
                    $minutes = $chargeDetail->minutes;
                }
                $this->data['use_fee'] = round($this->data['duration'] / ($minutes * 60), 2);
                if ($order->power_fee <= $this->data['use_fee']) {
                    $requestData = [
                        'fd' => $this->fd,
                        'sn' => $order->sn,
                        'channel_number' => $order->channel_number, // 假设端口号，根据实际情况调整
                        'number' => $order->number,
                        'balance' => 0 // 根据需要设置余额
                    ];
                    $this->sendStop($requestData);
                }
            }
            if($order->charge && $order->charge->type == 2){
                $this->data['use_fee'] =($this->data['duration']/($order->minutes*60))*$order->power_fee;
            }
            if ($order->charge && $order->charge->type == 3) {
                $this->data['use_fee'] = round($this->data['elec'] * $order->charge->elec_price, 2);
                if ($order->charge->service_type == 1) {
                    $this->data['charge_service'] = round($this->data['elec'] * $order->charge->service_fee, 2);
                } else {
                    $chargeDetail = ChargeDetail::where('charge_option_id', $order->charge_id)
                        ->where('type', 3)
                        ->where('min_power', '<=', $order->power)
                        ->where('max_power', '>=', $order->power)
                        ->first();
                    $hour = $this->data['duration'] / 3600;
                    $this->data['charge_service'] = $hour * $chargeDetail->fee;
                }
                if ($order->power_fee <= $this->data['use_fee'] + $this->data['charge_service']) {
                    $requestData = [
                        'fd' => $this->fd,
                        'sn' => $order->sn,
                        'channel_number' => $order->channel_number, // 假设端口号，根据实际情况调整
                        'number' => $order->number,
                        'balance' => 0 // 根据需要设置余额
                    ];
                    $this->sendStop($requestData);
                }
            }
            // 使用 updateOrCreate 实现存在则更新，不存在则创建的逻辑
            if ($order->detail) {
                $order->detail->fill($this->data);
                $order->detail->save();
            } else {
                // 假设 OrderDetail 模型存在且与 Order 关联
                $orderDetail = new \App\Model\OrderDetail($this->data);
                $order->detail()->save($orderDetail);
            }
            $order->duration_seconds = $this->data['duration'];
            if($order->status > Order::STATUS_USING){
                $requestData = [
                    'fd' => $this->fd,
                    'sn' => $order->sn,
                    'channel_number' => $order->channel_number, // 假设端口号，根据实际情况调整
                    'number' => $order->number,
                    'balance' => 0 // 根据需要设置余额
                ];
                $this->sendStop($requestData);
            }
            $order->save();
        }catch (\Exception $e){
            Normal::logger(__METHOD__ . '充电进度处理异常: ' . json_encode($this->data).$e->getMessage().$e->getTraceAsString(), 'order-event');
        }
    }

    public function sendStop($data)
    {
        $response = DeviceService::postSelf('/tcp/stop', $data);
        if ($response->getStatusCode() != 200) {
            Normal::logger(__METHOD__ . '费用耗尽通知失败: ' . json_encode($this->data), 'order-event');
        }
    }


    public function handleStart()
    {
        $response = DeviceService::postTcp('/callback/start', $this->data);
        if ($response->getStatusCode() != 200) {
            Normal::logger(__METHOD__ . '通知失败: ' . json_encode($this->data), 'order-event');
        }
    }

    public function handleStop()
    {
        $response = DeviceService::postTcp('/callback/end', $this->data);
        if ($response->getStatusCode() != 200) {
            Normal::logger(__METHOD__ . '通知失败: ' . json_encode($this->data), 'order-event');
        }
    }

}
